﻿using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using Microsoft.Services.Clab.UI.Mvvmc.Properties;

namespace Microsoft.Services.Clab.UI.Mvvmc
{
    public sealed class ViewCollection : ObservableCollection<IView>
    {
        private IViewModel ownerViewModel;
        [ThreadStatic]
        private bool removing;

        #region MainView Property
        public IView MainView
        {
            get { return this.mainView; }
            private set { if (this.mainView != value) { this.mainView = value; this.OnPropertyChanged(new PropertyChangedEventArgs("MainView")); } }
        }
        private IView mainView;
        #endregion

        public ViewCollection(IViewModel owner)
        {
            this.ownerViewModel = owner;
        }

        public void AddMainView(IView view)
        {
            if (this.MainView == null)
            {
                this.Add(view);
                this.MainView = view;
            }
            else
            {
                throw new InvalidOperationException(Resources.MainViewAlreadyAddedToCollection);
            }
        }

        protected override void InsertItem(int index, IView item)
        {
            base.InsertItem(index, item);

            if (item.State < ViewState.Initialized)
            {
                item.Initialize(this.ownerViewModel);
            }
        }

        protected override void SetItem(int index, IView item)
        {
            base.SetItem(index, item);

            if (item.State < ViewState.Initialized)
            {
                item.Initialize(this.ownerViewModel);
            }
        }

        protected override void ClearItems()
        {
            while (this.Count > 0)
            {
                this.RemoveItem(0);
            }
        }

        protected override void RemoveItem(int index)
        {
            try
            {
                this.removing = true;

                var item = base[index];
                if (item.State < ViewState.Disposing)
                {
                    item.Dispose();
                }
                base.RemoveItem(index);
            }
            finally
            {
                this.removing = false;
            }
        }

        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            base.OnCollectionChanged(e);

            if (e.NewItems != null)
            {
                foreach (var item in e.NewItems)
                {
                    var npc = item as INotifyPropertyChanged;
                    if (npc != null)
                    {
                        npc.PropertyChanged += OnItemPropertyChanged;
                    }
                }
            }

            if (e.OldItems != null)
            {
                foreach (var item in e.OldItems)
                {
                    var npc = item as INotifyPropertyChanged;
                    if (npc != null)
                    {
                        npc.PropertyChanged -= OnItemPropertyChanged;
                    }
                }
            }
        }

        private void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "State")
            {
                var item = sender as IView;
                if (item.State == ViewState.Disposed && !removing)
                {
                    this.Remove(item);
                }
            }
        }
    }
}